/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.debugger.support.nodes; import java.awt.Image; import java.awt.Toolkit; import java.beans.BeanInfo; import java.beans.PropertyChangeEvent; import java.lang.reflect.InvocationTargetException; import java.lang.ref.WeakReference; import java.util.ResourceBundle; import java.util.HashMap; import java.util.ArrayList; import java.util.Arrays; import javax.swing.SwingUtilities; import org.openide.TopManager; import org.openide.actions.PropertiesAction; import org.openide.actions.ToolsAction; import org.openide.debugger.DebuggerException; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.nodes.Children; import org.openide.nodes.AbstractNode; import org.openide.nodes.PropertySupport; import org.openide.util.NbBundle; import org.openide.util.Mutex; import org.openide.util.actions.SystemAction; import org.netbeans.modules.debugger.support.DebuggerModule; import org.netbeans.modules.debugger.support.AbstractThread; import org.netbeans.modules.debugger.support.AbstractThreadGroup; import org.netbeans.modules.debugger.support.ThreadGroupAdapter; import org.netbeans.modules.debugger.support.ThreadGroupListener; import org.netbeans.modules.debugger.support.actions.SuspendCookie; import org.netbeans.modules.debugger.support.actions.SuspendAction; import org.netbeans.modules.debugger.support.actions.ResumeAction; /** * This class represents threadGroup as a Node. * This class is final only for performance reasons, * can be happily unfinaled if desired. * * @author Jan Jancura */ public final class ThreadGroupNode extends AbstractNode implements SuspendCookie { /** generated Serialized Version UID */ static final long serialVersionUID = -4736310787523747464L; // static .................................................................... /** Property names */ public static final String PROP_GROUP_NAME = "threadName"; // NOI18N protected static Image threadGroupIcon; protected static Image threadGroupCurrentIcon; /** System actions of this node */ private static SystemAction[] staticActions; /** Icon paths. */ protected static final String ICON_CURRENT = "/org/netbeans/modules/debugger/resources/threadGroupCurrent"; // NOI18N protected static final String ICON_BASE = "/org/netbeans/modules/debugger/resources/threadGroup"; // NOI18N private static ResourceBundle bundle; // variables ................................................................. private transient AbstractThreadGroup threadGroup; private transient TGListener TGListener; /** Where to add variables. */ private VariableHome variableHome; private boolean current = false; // init ...................................................................... /** * Creates thread group context with given thread group */ public ThreadGroupNode ( VariableHome variableHome, AbstractThreadGroup threadGroup ) { super (new ThreadGroupContextChildren (variableHome)); this.variableHome = variableHome; this.threadGroup = threadGroup; try { String s; setDisplayName (s = threadGroup.getName ()); setName (s); } catch (DebuggerException e) { String s; setDisplayName (s = getLocalizedString ("CTL_Thread_group")); setName (s); } initialize(); } /** * Remove listeners. */ protected void finalize () { threadGroup.removeThreadGroupListener (TGListener); } private void initialize () { current = threadGroup.isCurrent (); if (current) setIconBase (ICON_CURRENT); else setIconBase (ICON_BASE); createProperties(); getCookieSet ().add (this); if (TGListener == null) TGListener = new TGListener (this); threadGroup.addThreadGroupListener (TGListener); } // Node implementation ....................................................... /** Getter for set of actions that should be present in the * popup menu of this node. This set is used in construction of * menu returned from getContextMenu and specially when a menu for * more nodes is constructed. * * @return array of system actions that should be in popup menu */ public SystemAction[] getActions () { if (staticActions == null) staticActions = new SystemAction[] { SystemAction.get (SuspendAction.class), SystemAction.get (ResumeAction.class), null, SystemAction.get (ToolsAction.class), SystemAction.get (PropertiesAction.class) }; return staticActions; } /** Obtain handle for this node (for serialization). * The handle can be serialized and {@link Handle#getNode} used after * deserialization to obtain the original node. * * @return the handle, or <code>null</code> if this node is not persistable */ public Node.Handle getHandle () { return new ThreadsHandle (); } /** Creates property sets */ private void createProperties () { // default sheet with "properties" property set // NOI18N Sheet sheet = Sheet.createDefault (); Sheet.Set ps = sheet.get (Sheet.PROPERTIES); ps.put (new PropertySupport.ReadOnly ( PROP_GROUP_NAME, String.class, getLocalizedString ("PROP_group_name"), getLocalizedString ("HINT_group_name") ) { public Object getValue () throws InvocationTargetException { try { return threadGroup.getName (); } catch (Exception e) { throw new InvocationTargetException (e); } } }); // and set new sheet setSheet(sheet); } public void destroy () throws java.io.IOException { super.destroy (); threadGroup.removeThreadGroupListener (TGListener); } // SuspendCookie ............................................................. /** * Returns state of thread. */ public boolean isSuspended () { // throw new InternalError (); return false; } /** * Sets state of thread. */ public void setSuspended (boolean suspended) { threadGroup.setSuspended (suspended); } // helper methods ............................................................ /** * @return localized string. */ static String getLocalizedString (String s) { if (bundle == null) bundle = NbBundle.getBundle (ThreadGroupNode.class); return bundle.getString (s); } AbstractThreadGroup getDebuggerThreadGroup () { return threadGroup; } void changeProperties () { if ((threadGroup == null) || (current == threadGroup.isCurrent ())) return; current = threadGroup.isCurrent (); if (current) setIconBase (ICON_CURRENT); else setIconBase (ICON_BASE); } // inner classes ............................................................. private static class TGListener extends ThreadGroupAdapter { private WeakReference node; private AbstractThreadGroup threadGroup; TGListener (ThreadGroupNode n) { node = new WeakReference (n); threadGroup = n.threadGroup; } public void threadGroupCreated (AbstractThreadGroup dtg) { updateChindren (); } public void threadGroupDeath (AbstractThreadGroup dtg) { updateChindren (); } public void threadCreated (AbstractThread tg) { updateChindren (); } public void threadDeath (AbstractThread dt) { updateChindren (); } public void propertyChange (PropertyChangeEvent e) { ThreadGroupNode tgn = getTG (); if (tgn == null) return; tgn.changeProperties (); updateChindren (); } private void updateChindren () { ThreadGroupNode tgn = getTG (); if (tgn == null) return; ThreadGroupContextChildren myChildren = (ThreadGroupContextChildren) tgn.getChildren (); myChildren.update (); } private ThreadGroupNode getTG () { ThreadGroupNode tgn = (ThreadGroupNode) node.get (); if (tgn == null) threadGroup.removeThreadGroupListener (this); return tgn; } } /** Special Thread group context subnodes (children) */ private static final class ThreadGroupContextChildren extends Children.Keys { /** Where to add variables. */ private VariableHome variableHome; private boolean initialized = false; ThreadGroupContextChildren (VariableHome variableHome) { this.variableHome = variableHome; } /** Create a node for one data object. * @param key DataObject */ protected Node[] createNodes (Object key) { if (key instanceof AbstractThreadGroup) return new Node [] { new ThreadGroupNode (variableHome, (AbstractThreadGroup) key) }; else return new Node [] { new ThreadNode (variableHome, (AbstractThread) key) }; } /** Initializes the children. */ protected void addNotify () { initialized = true; AbstractThreadGroup threadGroup = ((ThreadGroupNode) getNode ()). threadGroup; TGListener TGListener = ((ThreadGroupNode) getNode ()).TGListener; if (TGListener == null) TGListener = ((ThreadGroupNode) getNode ()).TGListener = new TGListener ( (ThreadGroupNode) getNode () ); threadGroup.addThreadGroupListener (TGListener); update (); } /** Deinitializes the children. */ protected void removeNotify () { AbstractThreadGroup threadGroup = ((ThreadGroupNode) getNode ()). threadGroup; TGListener TGListener = ((ThreadGroupNode) getNode ()).TGListener; threadGroup.removeThreadGroupListener (TGListener); setKeys (java.util.Collections.EMPTY_SET); initialized = false; } void update () { if (!initialized) return; // add existing threads and groups ... AbstractThreadGroup threadGroup = ((ThreadGroupNode) getNode ()). threadGroup; AbstractThreadGroup[] groups = threadGroup.getThreadGroups (); AbstractThread[] threads = threadGroup.getThreads (); ArrayList l = new ArrayList (); l.addAll (Arrays.asList (groups)); l.addAll (Arrays.asList (threads)); setKeys (l); } } // end of ThreadGroupContextChildren inner class /** * Serializable node reference. */ private static class ThreadsHandle implements Node.Handle { static final long serialVersionUID = -4518262935887219735L; /** Reconstitute the node for this handle. * * @return the node for this handle * @exception IOException if the node cannot be created */ public Node getNode () { return DebuggerModule.getThreadGroupsRootNode (); } } } /* * Log * 12 Gandalf-post-FCS1.10.3.0 3/28/00 Daniel Prusa * 11 Gandalf 1.10 1/14/00 Daniel Prusa NOI18N * 10 Gandalf 1.9 1/13/00 Daniel Prusa NOI18N * 9 Gandalf 1.8 1/6/00 Jan Jancura Refresh of Threads & * Watches, Weakization of Nodes * 8 Gandalf 1.7 12/23/99 Daniel Prusa Bug 4557 * 7 Gandalf 1.6 11/8/99 Jan Jancura Somma classes renamed * 6 Gandalf 1.5 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 5 Gandalf 1.4 10/1/99 Jan Jancura Bug 3677 * 4 Gandalf 1.3 9/3/99 Jan Jancura * 3 Gandalf 1.2 9/2/99 Jan Jancura * 2 Gandalf 1.1 8/18/99 Jan Jancura Localization & Current * thread & Current session * 1 Gandalf 1.0 8/17/99 Jan Jancura * $ */